
#include "SettingsKeeper.h"

using namespace std;
using namespace ttg;
using namespace ttg::services;
using namespace ttg::structures;
using namespace ttg::extras;

//--------------------
//--- SettingsUnit ---
//--------------------

SettingsUnit::SettingsUnit(const char *name,
						   const char *description,
						   int param1, int param2)
	:NamedObject(name)
{
	this->description = description;
	this->param1 = param1;
	this->param2 = param2;
}

const char *SettingsUnit::getDescription() const
{
	return description.data();
}

int SettingsUnit::getParam1() const
{
	return param1;
}

int SettingsUnit::getParam2() const
{
	return param2;
}

SettingsUnit::~SettingsUnit()
{
	//nothing
}

//----------------
//--- Settings ---
//----------------

Settings::Settings(const char *name,
				   const char *description)
	:NamedObject(name)
{
	description = description;
	data = Dictionary<SettingsUnit>::create(10);
	chosen = NULL;
}

void Settings::add(SettingsUnit *su)
{
	data->add(su);
}

SettingsUnit *Settings::setChosen(SettingsUnit *su)
{
	return chosen = su;
}

const SettingsUnit &Settings::getChosen() const
{
	if (chosen != NULL)
		return *chosen;
	else
		throw Error(Error::LOCAL, "SettingsUnit", "getChosen", "The chosen unit isn't set");
}

Settings::~Settings()
{
	delete data;
}

SettingsUnit &Settings::getCurrent()
{
	return *chosen;
}

const SettingsUnit &Settings::getCurrent() const
{
	return *chosen;
}

//----------------------
//--- SettingsKeeper ---
//----------------------

SettingsKeeper *SettingsKeeper::ref = NULL;

//private

void SettingsKeeper::add(Settings *s)
{
	data->add(s);
}

void SettingsKeeper::configure(XMLTree &xml)
{
	Settings *s;
	bool windowed;
	bool intro;
	int blocks;
	if (!xml.openSection("Settings"))
		throw Error(Error::FATAL, "SettingsKeeper", "configure", "Cannot find \"Settings\" section");
	//------------
	//Game section
	if (!xml.openSection("Game") ||
		!xml.getBoolAttribute("Windowed", windowed) ||
		!xml.getBoolAttribute("Intro", intro) ||
		!xml.getIntAttribute("Blocks", blocks))
		throw Error(Error::FATAL, "SettingsKeeper", "configure", "Cannot find correct \"Game\" section");
	//Blocks
	s = new Settings("CUBES_COUNT", "Count of test cubes");
	s->add(s->setChosen(new SettingsUnit("Default",
										 "NOT AVAIBLE",
										 blocks - 1, 0)));
	add(s);
	xml.closeSection();
	//-------------
	//Video section
	int adapter;
	const char *aspect;
	const char *res;
	const char *aa;
	if (!xml.openSection("Video") ||
		!xml.getIntAttribute("Adapter", adapter) ||
		!xml.getStringAttribute("AspectRatio", aspect) ||
		!xml.getStringAttribute("Resolution", res) ||
		!xml.getStringAttribute("Antialiasing", aa))
		throw Error(Error::FATAL, "SettingsKeeper", "configure", "Cannot find correct \"Video\" section");
	//Adapter
	s = new Settings("ADAPTER", "NOT AVAIBLE");
	s->add(s->setChosen(
		   new SettingsUnit("Default",
							"NOT AVAIBLE",
							adapter, 0)));
	add(s);
	//aspect
	strings::StringSplitter sp1;
	sp1.setSplitter('*', false);
	sp1.setString(aspect);
	s = new Settings("ASPECT", "NOT AVAIBLE");
	s->add(s->setChosen(
			new SettingsUnit("Default",
							"NOT AVAIBLE",
							atoi(sp1[0]), atoi(sp1[1]))));
	add(s);
	//resolution
	strings::StringSplitter sp2;
	sp2.setSplitter('*', false);
	sp2.setString(res);
	s = new Settings("Resolution", "Screen resolution");
	s->add(s->setChosen(
			new SettingsUnit("Default",
							 "NOT AVAIBLE",
							 atoi(sp2[0]), atoi(sp2[1]))));
	add(s);
	//AA
	int aa_type = 0;
	if (string("None") == aa)
		aa_type = 0; else
	if (string("NonMaskable") == aa)
		aa_type = 1; else
	if (string("TwoSamples") == aa)
		aa_type = 2; else
	if (string("FourSamples") == aa)
		aa_type = 4; else
	if (string("EightSamples") == aa)
		aa_type = 8;
	else
	{
		addLocalError("SettingsKeeper", "configure", "Cannot deteminate AntiAliasing type");
		aa_type = 0;
	}
	s = new Settings("ANTI_ALIASING", "NOT AVAIBLE");
	s->add(s->setChosen(
			new SettingsUnit("Default",
							 "NOT AVAIBLE",
							 aa_type, 1)));
	add(s);
	xml.closeSection();
	//------------------
	//Perfomance section
	int threadcount;
	if (!xml.openSection("Perfomance") ||
		!xml.getIntAttribute("Threads", threadcount))
		throw Error(Error::FATAL, "SettingsKeeper", "configure", "Cannot find correct \"Perfomance\" section");
	//ThreadCount
	s = new Settings("THREAD_COUNT", "NOT AVAIBLE");
	s->add(s->setChosen(
			new SettingsUnit("Default",
			 				 "NOT AVAIBLE",
							 threadcount, 0)));
	add(s);
	while (xml.openNextSection())
	{
		int core;
		const char *name;
		if (!xml.getIntAttribute("Core", core) ||
			!xml.getStringAttribute("Name", name))
			throw Error(Error::FATAL, "SettingsKeeper", "configure", "Cannot find correct \"Thread\" section");
		s = new Settings(name, "NOT AVAIBLE");
		s->add(s->setChosen(new SettingsUnit("Default",
											 "NOT AVAIBLE",
											 core, 0)));
		add(s);
		xml.closeSection();
	}
	xml.closeSection();
	xml.closeSection();
	//------
	//Others
	s = new Settings("Refresh rate", "Rate of horizontal display refreshing");
	s->add(s->setChosen(new SettingsUnit("Default", "Will be defined by OS", 0)));
	s->add(new SettingsUnit("65Hz", "Chose this in case of old monitor", 65));
	s->add(new SettingsUnit("75Hz", "Optimal rate", 75));
	add(s);
	s = new Settings("CPU_THREAD_DIFFICULTY", "Difficulty of the tasks, which must be taken and performed by one thread");
	s->add(s->setChosen(new SettingsUnit("50%", "All tasks will be performed after two iterations", 50)));
	add(s);
	s = new Settings("EXPECTED_FPS", "Ideal value for FPS.");
	s->add(s->setChosen(new SettingsUnit("30", "Comfort", 30)));
	add(s);
}

//public

void SettingsKeeper::startUnSafe(std::vector<Service *> &deps, const char *params)
{
	data = Dictionary<Settings>::create(50);
	if (params == NULL || string("ignore_settings_xml") != params)
		load("Settings.xml");
}

void SettingsKeeper::stopUnSafe()
{
	SAFE_DELETE(data);
}

SettingsKeeper::SettingsKeeper()
	:Service("SettingsKeeper", "Logger", false)
{
	data = NULL;
	makeRegistration();
}

void SettingsKeeper::load(const char *filename)
{
	TTGXMLTree xml;
	try
	{
		xml.assign(XMLTree::XML_RO, filename);
		configure(xml.getSubXMLTree());
		xml.close();
	}
	catch (Error &)
	{
		//addLocalError("SettingsKeeper", "load", "Cannot load settings. Wrong or corrupted file");
		return;//throw;
	}
}

void SettingsKeeper::save(const char *filename)
{
	throw Error(Error::FATAL, "not implemented yet");
}

const SettingsUnit &SettingsKeeper::getChosen(const char *name)
{
	Settings *s = data->get(name);
	if (s == NULL)
		throw Error(Error::FATAL, "SettingsKeeper", "getChousen", "Cannot find record", name);
	return s->getChosen();
}

SettingsKeeper::~SettingsKeeper()
{
	stop();
}
